package com.dronff.gvm.memorymanager;

import com.dronff.gvm.interfaces.Allocatable;
import com.dronff.gvm.interfaces.AllocatableMemory;
import com.dronff.gvm.interfaces.Hashable;
import com.dronff.gvm.interfaces.Offsetable;

import java.util.Arrays;

/**
 * @author: tyf
 * @date: 2022/9/9 10:01
 * @description: todo(
 */
public abstract class Memory implements Hashable, Offsetable {
    private byte[] memory;
    // 该内存的偏移量 如果不是子内存 该值为0
    private int offset;
    private int size;
    private int currentIndex;
    // 内存的父内存 parent和memory不能共存
    private AllocatableMemory parent;
    protected Memory(){
        offset = 0;
        size = 0;
        currentIndex = 0;
    }
    public Memory(int size){
        memory = new byte[size];
        offset = 0;
        this.size = size;
        currentIndex = 0;
    }
    protected Memory(AllocatableMemory parent,int size,int offset){
        if(parent == null){
            this.memory = new byte[size];
        }
        this.parent = parent;
        this.offset = offset;
        this.size = size;
        this.currentIndex = 0;
    }
    public void setParent(AllocatableMemory parent) throws IllegalAccessException {
        if(memory != null){
            throw new IllegalAccessException("Common memory The father memory cannot be set");
        }
        this.parent = parent;
    }

    public byte[] getMemory() {
        return memory;
    }

    public void setMemory(byte[] memory) {
        this.memory = memory;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public int getCurrentIndex() {
        return currentIndex;
    }

    public void setCurrentIndex(int currentIndex) {
        this.currentIndex = currentIndex;
    }

    public AllocatableMemory getParent() {
        return parent;
    }
    @Override
    public int getOffset() {
        if(parent != null){
            return offset + parent.getOffset();
        }
        return offset;
    }
    @Override
    public void setOffset(int offset) {
        this.offset = offset;
    }
    public boolean checkChildMemory(Memory memory){
        if(memory.getParent() == null || memory.getParent() != this){
            return true;
        }
        return false;
    }
    public int getSize(){
        return this.size;
    }
    @Override
    public int getHash() throws IndexOutOfBoundsException{
        if(parent == null && memory == null){
            throw new IndexOutOfBoundsException("getHash err :no parent and memory");
        }
        if(parent != null){
            return parent.getHash();
        }
        return Arrays.hashCode(memory);
    }
}
